home *** CD-ROM | disk | FTP | other *** search
/ Nothing but Tetris / Nothing but Tetris.iso / amiga / workbench_tris / tetris.c < prev    next >
C/C++ Source or Header  |  1992-11-19  |  15KB  |  458 lines

  1. /*
  2. Copyright (c) 1992, Trevor Smigiel.  All rights reserved.
  3.  
  4. (I hope Commodore doesn't mind that I borrowed their copyright notice.)
  5.  
  6. The source and executable code of this program may only be distributed in free
  7. electronic form, via bulletin board or as part of a fully non-commercial and
  8. freely redistributable diskette.  Both the source and executable code (including
  9. comments) must be included, without modification, in any copy.  This example may
  10. not be published in printed form or distributed with any commercial product.
  11.  
  12. This program is provided "as-is" and is subject to change; no warranties are
  13. made.  All use is at your own risk.  No liability or responsibility is assumed.
  14.  
  15. */
  16.  
  17. #include <exec/types.h>
  18. #include <exec/memory.h>
  19. #include <math.h>
  20. #include <stdio.h>
  21. #include "tetris.h"
  22.  
  23. #include <proto/exec.h>
  24. #include <proto/dos.h>
  25. #include <proto/graphics.h>
  26. #include <proto/intuition.h>
  27.  
  28. #include "main_protos.h"
  29. #include "TetrisImages_protos.h"
  30.  
  31. struct TBoard *
  32. NewBoard(struct RastPort *rp, WORD bleft, WORD btop)
  33. {
  34.     struct TBoard *board;
  35.     int i;
  36.  
  37.     board = AllocMem(sizeof(struct TBoard), MEMF_CLEAR);
  38.     if (board) {
  39.  
  40.         InitBitMap(&board->bitmap, Depth, PWidth, PHeight);
  41.         board->bitmap.Planes[0] = AllocMem(board->bitmap.BytesPerRow * board->bitmap.Rows * board->bitmap.Depth, MEMF_CHIP | MEMF_CLEAR);
  42.         if (board->bitmap.Planes[0]) {
  43.  
  44.             for (i = 1; i < Depth; i++) 
  45.                 board->bitmap.Planes[i] = board->bitmap.Planes[i-1] + board->bitmap.BytesPerRow;
  46.             board->bitmap.BytesPerRow *=  Depth;
  47.  
  48.             board->rastport = rp;
  49.  
  50.             board->board_off.x = bleft;
  51.             board->board_off.y = btop;
  52.             board->score_off.x = bleft;
  53.             board->score_off.y = 1 * (board->rastport->TxHeight + 1) + btop - YSize * 4;
  54.             board->line_off.x  = bleft;
  55.             board->line_off.y  = 3 * (board->rastport->TxHeight + 1) + btop - YSize * 4;
  56.             board->time_off.x  = bleft;
  57.             board->time_off.y  = 2 * (board->rastport->TxHeight + 1) + btop - YSize * 4;
  58.             board->next_off.x  = bleft + PWidth - XSize * 4;
  59.             board->next_off.y  = btop - ((YSize * 7) / 2);
  60.  
  61.             for (i = 0; i < PFHEIGHT; i++) {
  62.                 board->level.board[i] = 0x801f;
  63.             }
  64.             board->level.board[i] = 0xffff;
  65.             board->level.goal     = GOAL_TIME_LIMIT | GOAL_CLEAR_LINES;
  66.             board->level.lines    = 5;
  67.             board->level.time     = 60;
  68.             board->level.line_up  = 30;
  69.  
  70.             CurrentTime((LONG *)&board->seed[1], (LONG *)&board->seed[0]);
  71.  
  72.             board->next_which   = TFirst[nrand48(board->seed) % 7];
  73.             board->piece.which  = TFirst[nrand48(board->seed) % 7];
  74.             board->piece.bx     = (PFWIDTH / 2) - 2;
  75.             board->piece.x      = board->piece.bx * XSize;
  76.             board->piece.by     = 0;
  77.             board->piece.y      = 0;
  78.             board->next_sec     = UPDATE_SECONDS;
  79.             board->points       = 0;
  80.             board->clevel       = Level;
  81.             board->next_line_up = board->level.line_up;
  82.             board->drop_up      = 30;
  83.             board->next_drop_up = board->drop_up;
  84.             board->drop         = 10;
  85.             board->next_drop    = board->drop;
  86.  
  87.             board->lines        = board->level.lines;
  88.             board->time         = board->level.time;
  89.  
  90.             return board;
  91.         }
  92.         FreeMem(board, sizeof(struct TBoard));
  93.     }
  94.     return NULL;
  95. }
  96.  
  97. void 
  98. FreeBoard(struct TBoard *board)
  99. {
  100.     FreeMem(board->bitmap.Planes[0], board->bitmap.BytesPerRow * board->bitmap.Rows);
  101.     FreeMem(board, sizeof(struct TBoard));
  102. }
  103.  
  104. void 
  105. AddPiece(struct TBoard *board)
  106. {
  107.     UWORD piece = TPieces[board->piece.which], p;
  108.     UWORD *b = &board->level.board[board->piece.by];
  109.     WORD x = board->piece.bx + 1;
  110.     *b |= ((piece & 0xf000) >> x);
  111.     if (p = piece & 0x0f00) {
  112.         b++; x -= 4;
  113.         *b |= ((x >= 0) ? (p >> x) : (p << -x));
  114.         if (p = piece & 0x00f0) {
  115.             b++; x -= 4;
  116.             *b |= ((x >= 0) ? (p >> x) : (p << -x));
  117.             if (p = piece & 0x000f) {
  118.                 b++; x -= 4;
  119.                 *b |= ((x >= 0) ? (p >> x) : (p << -x));
  120.             }
  121.         }
  122.     }
  123. }
  124.  
  125. WORD
  126. TestMove(struct TBoard *board, WORD which, WORD x, WORD y)
  127. {
  128.     UWORD piece = TPieces[which];
  129.     UWORD *b = &board->level.board[y];
  130.     UWORD p;
  131.     x++;
  132.     if (*b & ((piece & 0xf000) >> x)) return 0;
  133.     if (p = piece & 0x0f00) {
  134.         b++; x -= 4;
  135.         if (*b & ((x >= 0) ? (p >> x) : (p << -x))) return 0;
  136.         if (p = piece & 0x00f0) {
  137.             b++; x -= 4;
  138.             if (*b & ((x >= 0) ? (p >> x) : (p << -x))) return 0;
  139.             if (p = piece & 0x000f) {
  140.                 b++; x -= 4;
  141.                 if (*b & ((x >= 0) ? (p >> x) : (p << -x))) return 0;
  142.             }
  143.         }
  144.     }
  145.     return 1;
  146. }
  147.  
  148. void 
  149. CheckRows(struct TBoard *board, WORD btop, WORD pheight)
  150. {
  151.     UWORD *b, *src, *dst;
  152.     WORD top, height, ymax;
  153.     int first;
  154.     int i, j;
  155.     char buf[12];
  156.     int pt = 0;
  157.  
  158.     top = 0;
  159.     for (i = btop - 1; board->level.board[i] & 0x7fe0; i--);
  160.     first = i + 1;
  161.     top = first * YSize;
  162.     height = (btop - first) * YSize;
  163.     ymax = board->board_off.y + top + height + YSize - 1;
  164.     for (b = &board->level.board[btop], i = 0; i < pheight; i++, b++) {
  165.         if (*b == 0xffff) { 
  166.             if (height)
  167.                 BltBitMap(&board->bitmap, 0, top, &board->bitmap, 0, top + YSize, PWidth, height, 0xC0, 0xff, NULL);
  168.             BltClear(board->bitmap.Planes[0] + top * board->bitmap.BytesPerRow, board->bitmap.BytesPerRow * YSize, 0);
  169.             ScrollRaster(board->rastport, 0, -YSize, board->board_off.x, board->board_off.y + top, board->board_off.x + PWidth - 1, ymax);
  170.             for (src = b - 1, dst = b, j = i + btop - first; j > 0; j--)
  171.                 *dst-- = *src--;
  172.             board->level.board[first] = 0x801f;
  173.             top += YSize;
  174.             first++;
  175.  
  176.             pt++;
  177.             board->points += pt;
  178.             sprintf(buf, "Score:%4d", board->points);
  179.             Move(board->rastport, board->score_off.x, board->score_off.y);
  180.             Text(board->rastport, buf, 10);
  181.  
  182.             board->lines--; 
  183.             sprintf(buf, "Lines:%4d", board->lines);
  184.             Move(board->rastport, board->line_off.x, board->line_off.y);
  185.             Text(board->rastport, buf, 10);
  186.             if ((board->level.goal & GOAL_CLEAR_LINES) && (board->lines <= 0)) {
  187.                 board->flags |= TETF_NEXTLEVEL;
  188.             }
  189.         } else {
  190.             height += YSize;
  191.         }
  192.         ymax += YSize;
  193.     }
  194. }
  195.  
  196. void 
  197. PrintBits(struct TBoard *board)
  198. {
  199.     int i, j;
  200.     for (i = 0; i <= PFHEIGHT; i++) {
  201.         for (j = 0x4000; j & 0x7fe0; j >>= 1)
  202.             printf((j & board->level.board[i]) ? "1" : "0");
  203.         printf("\n");
  204.     }
  205.     printf("\n");
  206. }
  207.  
  208. void  
  209. MoveTetris(struct TBoard *board, WORD move)
  210. {
  211.     struct TPiece npiece;
  212.     WORD left, top, width, height;
  213.  
  214.     if ((board) && (board->flags & (TETF_GAMEOVER | TETF_NEXTLEVEL))) return;
  215.  
  216.     npiece = board->piece;
  217.  
  218.     left = board->piece.x;
  219.     top = board->piece.y;
  220.     width = TSizes[board->piece.which].x;
  221.     height = TSizes[board->piece.which].y;
  222.  
  223.     switch (move) {
  224.     case COMMAND_DOWN:
  225.         npiece.by++;
  226.         npiece.y += YSize;
  227.         height += YSize;
  228.         break;
  229.     case COMMAND_LEFT:
  230.         npiece.bx--;
  231.         npiece.x -= XSize;
  232.         left -= XSize;
  233.         width += XSize;
  234.         break;
  235.     case COMMAND_RIGHT:
  236.         npiece.bx++;
  237.         npiece.x += XSize;
  238.         width += XSize;
  239.         break;
  240.     case COMMAND_ROTATE:
  241.         npiece.which = TNext[npiece.which];
  242.         if (TSizes[npiece.which].x > width)  width  = TSizes[npiece.which].x;
  243.         if (TSizes[npiece.which].y > height) height = TSizes[npiece.which].y;
  244.         break;
  245.     default: break;
  246.     }
  247.     if (TestMove(board, npiece.which, npiece.bx, npiece.by)) {
  248.         BltBitMap(&TBitMaps[board->piece.which], 0, 0, &board->bitmap, board->piece.x, board->piece.y, TSizes[board->piece.which].x, TSizes[board->piece.which].y, 0x22, 0xff, NULL);
  249.         board->piece = npiece;
  250.         BltBitMap(&TBitMaps[npiece.which], 0, 0, &board->bitmap, board->piece.x, board->piece.y, TSizes[npiece.which].x, TSizes[npiece.which].y, 0xEE, 0xff, NULL);
  251.         WaitTOF();
  252.         BltBitMapRastPort(&board->bitmap, left, top, board->rastport, board->board_off.x + left, board->board_off.y + top, width, height, 0xC0);
  253.     } else if (move == COMMAND_DOWN) {
  254.         AddPiece(board);
  255.         CheckRows(board, board->piece.by, TSSizes[board->piece.which].y);
  256.         board->piece.bx = (PFWIDTH / 2) - 2;
  257.         board->piece.x = board->piece.bx * XSize;
  258.         board->piece.by = 0;
  259.         board->piece.y = 0;
  260.         board->piece.which = board->next_which;
  261.         board->next_which = TFirst[nrand48(board->seed) % 7];
  262.         //board->pieces[board->piece.which]++;
  263.         BltBitMap(&TBitMaps[board->piece.which], 0, 0, &board->bitmap, board->piece.x, board->piece.y, TSizes[board->piece.which].x, TSizes[board->piece.which].y, 0xEE, 0xff, NULL);
  264.         BltBitMapRastPort(&board->bitmap, board->piece.x, board->piece.y, board->rastport, board->board_off.x + board->piece.x, board->board_off.y + board->piece.y, TSizes[board->piece.which].x, TSizes[board->piece.which].y, 0xC0);
  265.         BltBitMapRastPort(&TBitMaps[board->piece.which], 0, 0, board->rastport, board->next_off.x, board->next_off.y, TSizes[board->piece.which].x, TSizes[board->piece.which].y, 0x22);
  266.         BltBitMapRastPort(&TBitMaps[board->next_which], 0, 0, board->rastport, board->next_off.x, board->next_off.y, TSizes[board->next_which].x, TSizes[board->next_which].y, 0xC0);
  267.         if (!TestMove(board, board->piece.which, board->piece.bx, board->piece.by))
  268.             board->flags |= TETF_GAMEOVER | TETF_OUTOFROOM;
  269.     }
  270. }
  271.  
  272. void 
  273. DrawLine(struct TBoard *board, WORD line)
  274. {
  275.     int i, top, left, size = YSize * board->bitmap.BytesPerRow;
  276.  
  277.     BltClear(board->bitmap.Planes[0] + line * size, size, 0);
  278.  
  279.     top = line * YSize;
  280.     for (left = 0, i = 0x4000; i & 0x7fe0; i >>= 1, left += XSize) {
  281.         if (board->level.board[line] & i)
  282.             BltBitMap((struct BitMap *)&TBitMaps[19], 0, 0, &board->bitmap, left, top, XSize, YSize, 0xC0, 0xff, NULL);
  283.     }
  284. }
  285.  
  286. /* called every timer event, (every 1/10th of a second) */
  287. void 
  288. UpdateTetris(struct TBoard *board)
  289. {
  290.     int i;
  291.     char buf[12];
  292.  
  293.     if ((board) && (board->flags & (TETF_GAMEOVER | TETF_NEXTLEVEL))) return;
  294.  
  295.     board->next_drop--;
  296.     if (board->next_drop < 0) {
  297.         board->next_drop = board->drop;
  298.         MoveTetris(board, COMMAND_DOWN);
  299.     }
  300.  
  301.     board->next_sec--;
  302.     if (board->next_sec < 0) {
  303.         board->next_sec = UPDATE_SECONDS;
  304.  
  305.         board->time--;
  306.  
  307.         sprintf(buf, "Time:%2d:%02d", board->time / 60, board->time % 60);
  308.         Move(board->rastport, board->time_off.x, board->time_off.y);
  309.         Text(board->rastport, buf, 10);
  310.  
  311.         if (board->time <= 0) {
  312.             if (board->level.goal & GOAL_TIME_LIMIT)
  313.                 board->flags |= TETF_GAMEOVER | TETF_OUTOFTIME;
  314.             else if (board->level.goal & GOAL_ENDURANCE)
  315.                 board->flags |= TETF_NEXTLEVEL;
  316.         }
  317.  
  318.  
  319.         board->next_line_up--;
  320.         if (board->next_line_up < 0) {
  321.             board->next_line_up = board->level.line_up;
  322.  
  323.             for (i = 0; i < PFHEIGHT; i++)
  324.                 board->level.board[i] = board->level.board[i + 1];
  325.             board->level.board[PFHEIGHT - 1] &= ~(0x20 << (lrand48() % 10));
  326.  
  327.             /* move piece up */
  328.             if (board->piece.by) {
  329.                 board->piece.by--;
  330.                 board->piece.y -= YSize;
  331.             } else {
  332.                 /* Erase piece */
  333.                 BltBitMap(&TBitMaps[board->piece.which], 0, 0, &board->bitmap, board->piece.x, board->piece.y, TSizes[board->piece.which].x, TSizes[board->piece.which].y, 0x22, 0xff, NULL);
  334.                 /* Redraw piece down one so that its in the right place when the board is scrolled up */
  335.                 BltBitMap(&TBitMaps[board->piece.which], 0, 0, &board->bitmap, board->piece.x, board->piece.y + YSize, TSizes[board->piece.which].x, TSizes[board->piece.which].y, 0xEE, 0xff, NULL);
  336.             }
  337.             /* scroll board up */
  338.             BltBitMap(&board->bitmap, 0, YSize, &board->bitmap, 0, 0, PWidth, PHeight - YSize, 0xC0, 0xff, NULL);
  339.             /* draw the new line */
  340.             DrawLine(board, PFHEIGHT - 1);
  341.             /* update entire board to screen */
  342.             BltBitMapRastPort(&board->bitmap, 0, 0, board->rastport, board->board_off.x, board->board_off.y, PWidth, PHeight, 0xC0);
  343.         }
  344.  
  345.         board->next_drop_up--;
  346.         if (board->next_drop_up < 0) {
  347.             board->next_drop_up = board->drop_up;
  348.             if (board->drop) board->drop--;
  349.         }
  350.     }
  351. }
  352.  
  353. void
  354. DrawBoard(struct TBoard *board)
  355. {
  356.     int len;
  357.     char buf[12];
  358.  
  359.     SetAPen(board->rastport, 3);
  360.     RectFill(board->rastport, board->board_off.x - BSize, board->board_off.y, board->board_off.x, board->board_off.y + PHeight + BSize - 1);
  361.     RectFill(board->rastport, board->board_off.x - 1, board->board_off.y + PHeight, board->board_off.x + PWidth, board->board_off.y + PHeight + BSize - 1);
  362.     RectFill(board->rastport, board->board_off.x + PWidth, board->board_off.y, board->board_off.x + PWidth + BSize - 1, board->board_off.y + PHeight + BSize - 1);
  363.     SetAPen(board->rastport, 2);
  364.     Move(board->rastport, board->board_off.x - 1, board->board_off.y);
  365.     Draw(board->rastport, board->board_off.x - BSize, board->board_off.y);
  366.     Draw(board->rastport, board->board_off.x - BSize, board->board_off.y + PHeight + BSize - 1);
  367.     SetAPen(board->rastport, 1);
  368.     Move(board->rastport, board->board_off.x - BSize + 1, board->board_off.y + PHeight + BSize - 1);
  369.     Draw(board->rastport, board->board_off.x + PWidth + BSize - 1, board->board_off.y + PHeight + BSize - 1);
  370.     Draw(board->rastport, board->board_off.x + PWidth + BSize - 1, board->board_off.y);
  371.     SetAPen(board->rastport, 2);
  372.     Draw(board->rastport, board->board_off.x + PWidth, board->board_off.y);
  373.     Draw(board->rastport, board->board_off.x + PWidth, board->board_off.y + PHeight);
  374.     Draw(board->rastport, board->board_off.x - 1, board->board_off.y + PHeight);
  375.     SetAPen(board->rastport, 1);
  376.     Draw(board->rastport, board->board_off.x - 1, board->board_off.y + 1);
  377.  
  378.     
  379.     BltBitMap(&TBitMaps[board->piece.which], 0, 0, &board->bitmap, board->piece.x, board->piece.y, TSizes[board->piece.which].x, TSizes[board->piece.which].y, 0xEE, 0xff, NULL);
  380.     BltBitMapRastPort(&board->bitmap, 0, 0, board->rastport, board->board_off.x, board->board_off.y, PWidth, PHeight, 0xC0);
  381.  
  382.     EraseRect(board->rastport, board->next_off.x, board->next_off.y, board->next_off.x + XSize * 4 - 1, board->next_off.y + YSize * 7 / 2 - 1);
  383.     BltBitMapRastPort(&TBitMaps[board->next_which], 0, 0, board->rastport, board->next_off.x, board->next_off.y, TSizes[board->next_which].x, TSizes[board->next_which].y, 0xC0);
  384.  
  385.     len = sprintf(buf, "Score:%4d", board->points);
  386.     Move(board->rastport, board->score_off.x, board->score_off.y);
  387.     Text(board->rastport, buf, len);
  388.  
  389.     len = sprintf(buf, "Lines:%4d", board->lines);
  390.     Move(board->rastport, board->line_off.x, board->line_off.y);
  391.     Text(board->rastport, buf, len);
  392.  
  393.     len = sprintf(buf, "Time:%2d:%02d", board->time / 60, board->time % 60);
  394.     Move(board->rastport, board->time_off.x, board->time_off.y);
  395.     Text(board->rastport, buf, len);
  396. }
  397.  
  398. void 
  399. StartLevel(struct TBoard *board, WORD l)
  400. {
  401.     int i;
  402.     char filename[32];
  403.     BPTR file;
  404.  
  405.     if ((board) && (board->flags & TETF_GAMEOVER)) return;
  406.  
  407.     BltClear(board->bitmap.Planes[0], board->bitmap.Rows * board->bitmap.BytesPerRow, 0);
  408.  
  409.     sprintf(filename, "tetris:levels/%d", l);
  410.     file = Open(filename, MODE_OLDFILE);
  411.     if (file) {
  412.         Read(file, &board->level, sizeof(struct TLevel));
  413.         Close(file);
  414.         for (i = 0; i < PFHEIGHT; i++) {
  415.             DrawLine(board, i);
  416.         }
  417.     } else {    
  418.  
  419.         board->level.goal     = GOAL_TIME_LIMIT | GOAL_CLEAR_LINES;
  420.         board->level.lines    = 5  + l * 5;
  421.         board->level.time     = 60 + l * 30;
  422.         board->level.line_up  = 45 - l * 5 / 2;
  423.  
  424.         for (i = 0; i < PFHEIGHT; i++) {
  425.         board->level.board[i] = 0x801f;
  426.         }
  427.         board->level.board[i] = 0xffff;
  428.     }
  429.  
  430.     board->flags       &= ~TETF_NEXTLEVEL;
  431.     board->lines        = 0;
  432.     board->next_which   = TFirst[nrand48(board->seed) % 7];
  433.     board->piece.which  = TFirst[nrand48(board->seed) % 7];
  434.     board->piece.bx     = (PFWIDTH / 2) - 2;
  435.     board->piece.x      = board->piece.bx * XSize;
  436.     board->piece.by     = 0;
  437.     board->piece.y      = 0;
  438. //    board->drop_up     -= 1;
  439. //    board->drop         = board->drop_up;
  440.     board->next_drop    = board->drop;
  441.     board->next_sec     = UPDATE_SECONDS;
  442.     board->lines        = board->level.lines;
  443.     board->time         = board->level.time;
  444.     board->next_line_up = board->level.line_up;
  445.     board->next_drop_up = board->drop_up;
  446.     board->clevel = l;
  447.  
  448.     DrawBoard(board);
  449.  
  450. }
  451.  
  452. /*
  453. void 
  454. EndLevel(struct TBoard *board)
  455. {
  456. }
  457. */
  458.